package com.csproj.system.service;


import com.csproj.basic.BasicService;
import com.csproj.basic.domain.Site;
import com.csproj.basic.repository.SiteRepository;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.exception.BaseAppException;
import com.csproj.siiat.base.common.util.poi.POIUtil;
import com.csproj.siiat.config.ApplicationProperties;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.domain.AuthorityInfo;
import com.csproj.system.domain.RoleInfo;
import com.csproj.system.domain.UserInfo;
import com.csproj.system.repository.RoleInfoRepository;
import com.csproj.system.repository.UserInfoRepository;
import com.csproj.system.service.dto.UserInfoDTO;
import com.csproj.system.service.mapper.UserInfoMapper;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Service Implementation for managing UserInfo.
 * 用户Service
 */
@Service
@Transactional
public class UserInfoService extends BasicService<UserInfoDTO> {


    private final Logger log = LoggerFactory.getLogger(UserInfoService.class);

    private final UserInfoRepository userInfoRepository;

    private final UserInfoMapper userInfoMapper;

    private final PasswordEncoder passwordEncoder;

    private final RoleInfoRepository roleInfoRepository;

    private final SiteRepository siteRepository;

    private final ApplicationProperties applicationProperties;

    private final SysLogsService sysLogsService;

    public UserInfoService(UserInfoRepository userInfoRepository,
                           UserInfoMapper userInfoMapper,
                           PasswordEncoder passwordEncoder,
                           RoleInfoRepository roleInfoRepository, SiteRepository siteRepository,
                           ApplicationProperties applicationProperties,
                           SysLogsService sysLogsService) {
        this.userInfoRepository = userInfoRepository;
        this.userInfoMapper = userInfoMapper;
        this.passwordEncoder = passwordEncoder;
        this.roleInfoRepository = roleInfoRepository;
        this.siteRepository = siteRepository;
        this.applicationProperties = applicationProperties;
        this.sysLogsService = sysLogsService;
    }

    /**
     * 保存用户信息
     *
     * @param userInfoDTO 用户DTO
     * @return result
     */
    public UserInfoDTO save(UserInfoDTO userInfoDTO) {
        log.debug("Request to save UserInfo : {}", userInfoDTO);
        UserInfo userInfo = userInfoMapper.toEntity(userInfoDTO);
        String userId = userInfoDTO.getId();
        //设置用户密码
        if (userId != null) {
            UserInfo oldUserInfo = userInfoRepository.findOne(userId);
            if (userInfo.getPassword() == null || userInfo.getPassword().equals("")) {
                userInfo.setPassword(oldUserInfo.getPassword());
            } else {
                userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
            }
        } else {
            userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
        }


        //设置用户的使用状态：禁用，启用，默认为启用
        Boolean isUse = userInfo.getUsedFlag();
        if (isUse == null && !"".equals(isUse)) {
            userInfo.setUsedFlag(true);
        }

        Set<RoleInfo> roleInfoSet = new HashSet<>();
        //用户添加角色
        if (userInfoDTO.getRoleInfoIds().length > 0) {
            for (String roleId : userInfoDTO.getRoleInfoIds()) {
                RoleInfo roleInfo = roleInfoRepository.findOne(roleId);
                roleInfoSet.add(roleInfo);
            }
            userInfo.setRoleInfos(roleInfoSet);
        }
//        userInfo.setType(1);
//        DomainUtils.setHistory(userInfo, UserInfo.class, userInfoDTO, UserInfoDTO.class);
        userInfo.setDeletedFlag(false);
        userInfo.setSiteId(userInfo.getSiteId());
        Site siteDto = siteRepository.findById(userInfo.getSiteId());
        if(siteDto!=null)
            userInfo.setSiteName(siteDto.getSiteName());
        else{
            userInfo.setSiteName("");
        }
        userInfo = userInfoRepository.save(userInfo);
        UserInfoDTO result = userInfoMapper.toDto(userInfo);
        return result;
    }

    /**
     * 获取全部的可用用户信息
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<UserInfoDTO> findAll() {
        log.debug("Request to get all UserInfos");
        String siteId = getCurrentUserSiteId();
        List<UserInfoDTO> result;
        if (StringUtils.isNotBlank(siteId) && siteId != "nositeID") {
            result = userInfoRepository.findAllBySiteIdAndDeletedFlagIsFalseAndUsedFlagIsTrue(siteId).stream()
                    .map(n -> {
                        UserInfoDTO userInfoDTO = userInfoMapper.toDto(n);
                        return userInfoDTO;
                    }).collect(Collectors.toCollection(LinkedList::new));
        } else {
            result = userInfoRepository.findAllEnabled().stream()
                    .map(n -> {
                        UserInfoDTO userInfoDTO = userInfoMapper.toDto(n);
                        return userInfoDTO;
                    }).collect(Collectors.toCollection(LinkedList::new));
        }


        return result;
    }
    @Transactional(readOnly = true)
    public List<UserInfoDTO> findAllBySiteId(String siteId){
        List<UserInfoDTO> result = userInfoRepository.findAllBySiteIdAndDeletedFlagIsFalseAndUsedFlagIsTrue(siteId).stream()
                .map(n -> {
                    UserInfoDTO userInfoDTO = userInfoMapper.toDto(n);
                    return userInfoDTO;
                }).collect(Collectors.toCollection(LinkedList::new));
        return  result;
    }

    @Transactional(readOnly = true)
    public List<UserInfoDTO>  findUserByRoleId()
    {
        List<UserInfoDTO> result = userInfoRepository.getUserInfoByRoleInfoId("402880ef65e01bca0165e028cfdb0001").stream()
                .map(n -> {
                    UserInfoDTO userInfoDTO = userInfoMapper.toDto(n);
                    return userInfoDTO;
                }).collect(Collectors.toCollection(LinkedList::new));
        return  result;
    }


    /**
     * 获取用户信息（分页）
     *
     * @param queryParams
     * @param pageable    分页对象
     * @return
     */
    @Transactional(readOnly = true)
    public BaseDTO findPageList(Map<String, Object> queryParams, Pageable pageable) {
        log.debug("Request to get all UserInfos");

        Page<UserInfo> result = userInfoRepository.findPageList(queryParams, pageable);
        List<UserInfoDTO> userInfoDTOs = result.getContent().stream().
                map(n -> {
                    UserInfoDTO userInfoDTO = userInfoMapper.toDto(n);
                    return userInfoDTO;
                }).collect(Collectors.toList());
        Set<String> siteIds = new HashSet<>();
        userInfoDTOs.forEach(userInfoDTO -> {
            if (StringUtils.isNotBlank(userInfoDTO.getSiteId())) {
                siteIds.add(userInfoDTO.getSiteId());
            }

        });
        if (siteIds.size() > 0) {
            String[] siteIdArrs = new String[siteIds.size()];
            List<Site> sites = siteRepository.findByIds(siteIds.toArray(siteIdArrs));
            userInfoDTOs.forEach(userInfoDTO -> {
                if (StringUtils.isNotBlank(userInfoDTO.getSiteId())) {
                    Site site = sites.stream()
                            .filter(s -> s.getId().equals(userInfoDTO.getSiteId()))
                            .findFirst().orElse(new Site());
                    userInfoDTO.setSiteName(site.getSiteName());
                }
            });

        }

        return BaseDTO.createBaseDTO(result).setFieldList(userInfoDTOs);
    }

    /**
     * 获取用户信息
     *
     * @param id 用户id
     * @return userInfoDTO
     */
    @Transactional(readOnly = true)
    public UserInfoDTO findOne(String id) {
        log.debug("Request to get UserInfo : {}", id);
        UserInfo userInfo = userInfoRepository.findOne(id);
        UserInfoDTO userInfoDTO = userInfoMapper.toDto(userInfo);

        extendSiteName(userInfoDTO);
        return userInfoDTO;
    }

    /**
     * 获取用户信息
     *
     * @param id 用户id
     * @return userInfoDTO
     */
    @Transactional(readOnly = true)
    public List<String> getAuth(String id) {
        log.debug("Request to get UserInfo : {}", id);
        List<String> result = new ArrayList<>();
        Set<RoleInfo> roleInfoSet = new HashSet<>();
        UserInfo userInfo = userInfoRepository.findOne(id);
        Set<RoleInfo> roleInfos = userInfo.getRoleInfos();
        Iterator it = roleInfos.iterator();
        while (it.hasNext()) {
            RoleInfo roleInfo = (RoleInfo) it.next();
            Set<AuthorityInfo> authorityInfoSet = roleInfo.getAuthorityInfos();
            Iterator iterator = authorityInfoSet.iterator();
            while (iterator.hasNext()) {
                AuthorityInfo authorityInfo = (AuthorityInfo) iterator.next();
//                result.add(authorityInfo.getHref());
            }
        }
        return result;
    }

    /**
     * 删除用户信息
     *
     * @param id 用户id
     */
    public BaseDTO delete(String id) {
        log.debug("Request to delete UserInfo : {}", id);
        userInfoRepository.deleteUserInfo(id);
        //添加操作记录

        //保存用户操作
//        HttpClientUtil.request(historyDTO);
        return BaseDTO.createBaseDTO();
    }

    /**
     * 修改用户状态
     *
     * @param id    用户id
     * @param isUse 是否可用
     * @return
     */
    public UserInfoDTO changeUserIsUse(String id, Boolean isUse) {
        log.debug("Request to change UserInfo : {}", id);
        UserInfoDTO userInfoDTO = null;
        if (id != null && !"".equals(id) && isUse != null) {
            UserInfo userInfo = userInfoRepository.findOne(id);
            if (isUse) {
                userInfoRepository.setUserDisable(id);
            } else {
                userInfoRepository.setUserAble(id);
            }
            userInfoDTO = userInfoMapper.toDto(userInfo);
        }
        //添加操作记录

        return userInfoDTO;
    }

    /**
     * 批量删除用户
     *
     * @param ids 用户ids
     */
    public void deleteUserInfos(String[] ids) {


        //添加操作记录

        userInfoRepository.deleteUserInfoIds(ids);
    }


   /* @Transactional(readOnly = true)
    public UserInfo getUserWithAuthorities() {
        return userInfoRepository.findOneWithAuthoritiesByLogin(SecurityUtils.getCurrentUserName()).orElse(null);
    }*/


    /**
     * 设置用户的使用状态：禁用，启用，默认为启用
     *
     * @param userInfoDTO
     * @return
     */
    public UserInfoDTO updateUserInfoStatus(UserInfoDTO userInfoDTO) {
        log.debug("Request to update UserInfo isUse : {}", userInfoDTO);
        UserInfo userInfo = userInfoRepository.findOne(userInfoDTO.getId());
        Boolean isUse = userInfoDTO.getUsedFlag();
        if (isUse != null && !"".equals(isUse)) {
            userInfo.setUsedFlag(isUse);
        } else {
            userInfo.setUsedFlag(true);
        }
        userInfo.setRemark(userInfoDTO.getRemark());
        userInfo = userInfoRepository.save(userInfo);
        UserInfoDTO result = userInfoMapper.toDto(userInfo);

        UserInfo currentUser = getCurrentUser();
        if (userInfo.getUsedFlag()) {
            this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_change_user_state_enabled", "");
        } else {
            this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_change_user_state_disenabled", "");
        }

        return result;
    }

    /**
     * 修改密码
     *
     * @param userInfoDTO
     * @return
     */
    public BaseDTO updatePassword(UserInfoDTO userInfoDTO) {
        UserInfo currentUser = getCurrentUser();
        UserInfo userInfo = userInfoRepository.findOne(SecurityUtils.getCurrentUserId());
        if (!passwordEncoder.matches(userInfoDTO.getOldPass(), userInfo.getPassword())) {
            this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_old_pwd_error", "");
            return new BaseDTO(false, "old_pwd_error", null);
        }

        userInfo.setPassword(passwordEncoder.encode(userInfoDTO.getPassword()));
        userInfo = userInfoRepository.save(userInfo);
        //添加操作记录
        this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_change_pwd_success", "");
        //return new BaseDTO(200,"修改密码成功",userInfoMapper.toDto(userInfo));
        return BaseDTO.createBaseDTO().setResult(userInfoMapper.toDto(userInfo));
    }

    public BaseDTO setPassword(UserInfoDTO userInfoDTO) {
        UserInfo currentUser = getCurrentUser();
        UserInfo userInfo = userInfoRepository.findOne(userInfoDTO.getId());
        userInfo.setPassword(passwordEncoder.encode(userInfoDTO.getPassword()));
        userInfo = userInfoRepository.save(userInfo);
        //添加操作记录
        this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_set_pwd_success", "");
        //return new BaseDTO(200,"修改密码成功",userInfoMapper.toDto(userInfo));
        return BaseDTO.createBaseDTO().setResult(userInfoMapper.toDto(userInfo));
    }

    /**
     * 发送手机验证码
     *
     * @param phone
     * @param request
     * @return
     */
    public BaseDTO verificationCode(String phone, HttpServletRequest request) {
        Map<String, Object> param = new HashMap<>();
        String source = "1234567890";
        Random random = new Random();
        StringBuffer verificationCode = new StringBuffer("");
        //生成随机4位验证码
        for (int i = 0; i < 4; i++) {
            int index = Math.abs(random.nextInt() % 9);
            verificationCode.append(source.charAt(index));
        }
        param.put("mobile", phone);
        param.put("content", "您的验证码是:" + verificationCode + ",该码用于修改密码,请不要告诉他人,三十分钟内有效");
        //验证码存入用户remark字段
//        UserInfo userInfo = userInfoRepository.findByPhone(phone);
        return BaseDTO.createBaseDTO();
    }

    /**
     * 验证短信码
     *
     * @param dto
     * @return
     */
    public BaseDTO verificate(UserInfoDTO dto) {
        UserInfo userInfo = userInfoRepository.findByPhone(dto.getPhone());
//        if(StringUtils.isNotBlank(userInfo.getRemark()) && userInfo.getRemark().equals(dto.getCode())) {
//            userInfo.setPassword(passwordEncoder.encode(dto.getPassword()));
//            return new BaseDTO(200,"修改成功",null);
//        }
        return BaseDTO.createBaseDTO().setMessage("change_failed").setSuccess(false);
    }


    /**
     * 为新增用户添加bc角色
     *
     * @param userInfoIds
     * @return
     */
    public BaseDTO changeRoleInfoById(String userInfoIds) {
//        RoleInfo roleInfo = roleInfoRepository.findOne(16L);
        List<UserInfo> userInfos = new ArrayList<>();
        String ids[] = userInfoIds.split(",");
        for (int i = 0; i < ids.length; i++) {
            UserInfo userInfo = userInfoRepository.findOne(ids[i]);
            if (userInfo.getRoleInfos().size() > 0) {
                continue;
            }
            Set<RoleInfo> roleInfos = new HashSet<>();
//            roleInfos.add(roleInfo);
            userInfo.setRoleInfos(roleInfos);
            userInfos.add(userInfo);
            userInfoRepository.save(userInfo);
        }
        return BaseDTO.createBaseDTO().setResult(userInfos);
    }

    /**
     * 获取当前登陆用户站点ID，有中心管理员角色，返回null
     */
    public String getCurrentUserSiteId() {
        //根据角色确认查询
        String userInfoId = SecurityUtils.getCurrentUserId();
        UserInfo userInfo = userInfoRepository.findOne(userInfoId);
        Set<RoleInfo> roles = userInfo.getRoleInfos();
        String siteId = userInfo.getSiteId();
        RoleInfo roleInfo = roles.stream().filter(r -> r.getId().equals(applicationProperties.getCenterRole())).findFirst().orElse(null);
        if (roleInfo == null) {
            //没有中心管理员角色，查询时，添加限制条件，根据siteId查询
            if (StringUtils.isBlank(siteId)) {
                siteId = "nositeID";
            }
            return siteId;
        }

        return null;

    }

    /**
     * @param file
     * @return
     */
    public BaseDTO batchImport(MultipartFile file) {
        UserInfo currentUser = getCurrentUser();
        try {
            List<String[]> readResult = POIUtil.readExcel(file);
            if (readResult.size() == 0) {

                this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_upload_faild", "");
                return BaseDTO.createBaseDTO().setSuccess(false).setMessage("upload_faild");
            }
            List<UserInfo> userInfos = new ArrayList<>();
            StringBuilder errmsg = new StringBuilder();
            List<RoleInfo> roleInfos = roleInfoRepository.findAll();
            List<Site> sites = new ArrayList<>();
            Set<String> siteNames = readResult.stream().map(r -> StringUtils.trim(r[5])).collect(Collectors.toSet());
            if (siteNames.size() > 0) {
                sites = siteRepository.findByNames(siteNames);
            }
            int i = 2;
            for (String[] u : readResult) {
                try {

                    UserInfo uname = userInfoRepository.findByAccount(u[0]);
                    if (uname != null) {
                        errmsg.append(i - 1).append(",");
                    } else {
                        UserInfo userInfo = new UserInfo();
                        i++;
                        userInfo.setDeletedFlag(false);
                        userInfo.setUsedFlag(true);
                        userInfo.setAccount(u[0]);
                        if (StringUtils.isNotBlank(u[1])) {
                            userInfo.setPassword(passwordEncoder.encode(u[1]));
                        } else {
                            userInfo.setPassword(passwordEncoder.encode("123456"));
                        }

                        userInfo.setName(u[2]);
                        userInfo.setPhone(u[3]);
                        Set<RoleInfo> rs = roleInfos.stream().filter(r -> r.getName().equals(StringUtils.trim(u[4]))).collect(Collectors.toSet());
                        userInfo.setRoleInfos(rs);
                        Site site = sites.stream().filter(s -> s.getSiteName().equals(StringUtils.trim(u[5]))).findFirst().orElse(new Site());
                        userInfo.setSiteId(site.getId());
                        userInfo.setSiteName(site.getSiteName());
                        userInfos.add(userInfo);
                    }

                } catch (Exception e) {
                    errmsg.append(i - 1).append(",");
                }
            }

            if (userInfos.size() > 0)
                userInfoRepository.save(userInfos);
            String msg = "";
            if (errmsg.length() > 0) {
                //msg = org.apache.commons.lang3.StringUtils.truncate(errmsg.toString(),errmsg.length()-1);
                this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_upload_faild", "");
                return BaseDTO.createBaseDTO().setSuccess(false).setMessage("partial_upload_faild");
            }
        } catch (IOException e) {
            this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_upload_faild", "");
            throw new BaseAppException(false, "upload_error");
        }

        this.sysLogsService.saveForPost("", currentUser.getAccount() + ":user_upload_success", "");
        return BaseDTO.createBaseDTO().setSuccess(true);
    }
}
